package com.azh.server.vm;

import java.util.Arrays;

import com.azh.server.common.SubArray;
import com.azh.server.datam.dataItem.DataItem;
import com.azh.server.util.Parser;
import com.google.common.primitives.Bytes;

/**
 * @author zhaozhenhang <zhaozhenhang@kuaishou.com>
 * Created on 2022-04-30
 * 记录维护，mvcc 版本记录
 * 这儿没有提供更新操作，所以一条记录只有一个版本
 * 一条记录存储在DataItem中，所以Entry保存一个DataItem的引用
 */
public class Entry {

    private static final int of_tx_min = 0;

    private static final int of_tx_max = of_tx_min + 8;

    private static final int of_data = of_tx_max + 8;

    private long uid;
    private DataItem dataItem;
    private VersionManager vm;

    public static Entry newEntry(VersionManager vm, DataItem dm, long uid) {
        Entry entry = new Entry();
        entry.uid = uid;
        entry.dataItem = dm;
        entry.vm = vm;
        return entry;
    }

    public static Entry loadEntry(VersionManager vm, long uid) throws Exception {
        DataItem di = ((VersionManagerImpl) vm).dm.read(uid);
        return newEntry(vm, di, uid);
    }

    /**
     * txMin 是创建该记录的事物编号，txMax是删除该记录的事物编号
     * @param txId
     * @param data
     * @return
     */
    public static byte[] wrapEntryRaw(long txId, byte[] data) {
        byte[] txMin = Parser.longToByte(txId);
        byte[] txMax = new byte[8];
        return Bytes.concat(txMin, txMax, data);
    }

    public void release() {
        ((VersionManagerImpl) vm).releaseEntry(this);
    }

    public void remove() {
        dataItem.release();
    }

    public long getUid() {
        return uid;
    }

    /**
     * 以拷贝的形式返回内容
     * @return
     */
    public byte[] data() {
        dataItem.rLock();
        try {
            SubArray sa = dataItem.data();
            byte[] data = new byte[sa.end - sa.start - of_data];
            System.arraycopy(sa.raw, sa.start + of_data, data, 0, data.length);
            return data;
        }finally {
            dataItem.rUnLock();
        }
    }

    public long getTxMin() {
        dataItem.rLock();
        try {
            SubArray sa = dataItem.data();
            return Parser.parseLong(Arrays.copyOfRange(sa.raw, sa.start + of_tx_min, sa.start + of_tx_max));
        } finally {
            dataItem.rUnLock();
        }
    }

    public long getTxMax() {
        dataItem.rLock();
        try {
            SubArray sa = dataItem.data();
            return Parser.parseLong(Arrays.copyOfRange(sa.raw, sa.start + of_tx_max, sa.start + of_data));
        } finally {
            dataItem.rUnLock();
        }
    }

    public void setTxMax(long txId) {
        dataItem.before();
        try {
            SubArray sa = dataItem.data();
            System.arraycopy(Parser.longToByte(txId), 0, sa.raw, sa.start + of_tx_max, 8);
        } finally {
            dataItem.after(txId);
        }
    }

}
